package com.wbw.service;

import com.wbw.api.Flight;
import com.wbw.api.FlightService;
import lombok.extern.slf4j.Slf4j;

import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

@Service
@Component
@Slf4j
public class FlightServiceImpl implements FlightService {

    private List<Flight> flights;

    public FlightServiceImpl() {
        this.flights = loadFlightsFromXml();
    }

    private List<Flight> loadFlightsFromXml() {
        List<Flight> flightList = new ArrayList<>();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            InputStream is = getClass().getClassLoader().getResourceAsStream("flight.xml");
            if (is == null) {
                log.error("无法找到 flight.xml 文件");
                return flightList;
            }
            InputSource source = new InputSource(is);
            Document doc = builder.parse(source);

            XPathFactory xPathFactory = XPathFactory.newInstance();
            XPath xpath = xPathFactory.newXPath();

            NodeList flightNodes = (NodeList) xpath.compile("/flights/flight").evaluate(doc, XPathConstants.NODESET);
            for (int i = 0; i < flightNodes.getLength(); i++) {
                XPathExpression expr = xpath.compile("./*");
                NodeList fields = (NodeList) expr.evaluate(flightNodes.item(i), XPathConstants.NODESET);

                Flight flight = new Flight();
                for (int j = 0; j < fields.getLength(); j++) {
                    String tagName = fields.item(j).getNodeName();
                    String textContent = fields.item(j).getTextContent();
                    switch (tagName) {
                        case "flightcode":
                            flight.setFlightcode(textContent);
                            break;
                        case "company":
                            flight.setCompany(textContent);
                            break;
                        case "leaveairport":
                            flight.setLeaveairport(textContent);
                            break;
                        case "arriveairport":
                            flight.setArriveairport(textContent);
                            break;
                        case "leavetime":
                            flight.setLeavetime(textContent);
                            break;
                        case "arrivetime":
                            flight.setArrivetime(textContent);
                            break;
                        case "mode":
                            flight.setMode(textContent);
                            break;
                    }
                }
                flightList.add(flight);
            }
        } catch (Exception e) {
            log.error("解析 flight.xml 文件时出错", e);
        }
        return flightList;
    }

    public List<Flight> getAllFlights() {
        log.info("查询所有的航班信息！");
        return flights;
    }

    public List<Flight> getFlightsFromBeijing() {
        log.info("查询北京起飞的航班信息！");
        return filterFlightsByXPath("/flights/flight/leaveairport[text()='北京首都机场']");
    }

    public List<Flight> getFlightsToShanghai() {
        log.info("查询去上海的航班信息！");
        return filterFlightsByXPath("/flights/flight/arriveairport[text()='上海虹桥机场']");
    }

    public List<Flight> getEarlyMorningFlightsFromShanghai() {
        log.info("查询从上海出发的早航班信息！");
        return filterFlightsByXPath("/flights/flight[leaveairport='上海虹桥机场' and leavetime < '08:00']");
    }

    private List<Flight> filterFlightsByXPath(String xpathExpr) {
        List<Flight> result = new ArrayList<>();
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            InputStream is = getClass().getClassLoader().getResourceAsStream("flight.xml");
            if (is == null) {
                log.error("无法找到 flight.xml 文件");
                return result;
            }
            InputSource source = new InputSource(is);
            Document doc = builder.parse(source);

            XPathFactory xPathFactory = XPathFactory.newInstance();
            XPath xpath = xPathFactory.newXPath();

            XPathExpression expr = xpath.compile(xpathExpr);
            NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
            for (int i = 0; i < nodes.getLength(); i++) {
                org.w3c.dom.Node node = nodes.item(i).getParentNode();
                if ("flight".equals(node.getNodeName())) {
                    result.add(findFlightByNode(node));
                }
            }
        } catch (Exception e) {
            log.error("使用 XPath 过滤航班信息时出错", e);
        }
        return result;
    }

    private Flight findFlightByNode(org.w3c.dom.Node flightNode) {
        Flight flight = new Flight();
        NodeList children = flightNode.getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
            org.w3c.dom.Node child = children.item(i);
            if (child.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
                switch (child.getNodeName()) {
                    case "flightcode":
                        flight.setFlightcode(child.getTextContent());
                        break;
                    case "company":
                        flight.setCompany(child.getTextContent());
                        break;
                    case "leaveairport":
                        flight.setLeaveairport(child.getTextContent());
                        break;
                    case "arriveairport":
                        flight.setArriveairport(child.getTextContent());
                        break;
                    case "leavetime":
                        flight.setLeavetime(child.getTextContent());
                        break;
                    case "arrivetime":
                        flight.setArrivetime(child.getTextContent());
                        break;
                    case "mode":
                        flight.setMode(child.getTextContent());
                        break;
                }
            }
        }
        return flight;
    }
}